`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    12:33:34 04/05/2011 
// Design Name: 
// Module Name:    TopModule 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module TopModule(clk, reset);

	input clk;
	input reset;
	
	
	wire [15:0] net_MEMtoIF_branchAddr;
	wire [3:0] net_IDtoIF_JumpPC;
	wire [11:0] net_IDtoIF_JumpInstr;
	wire net_IDtoIF_doJump;
	wire net_MEMtoIF_doBra;
	
	wire [15:0] net_IFtoPipeline_PC;
	wire [15:0] net_IFtoPipeline_instr;
	
	wire [15:0] net_PipelinetoID_PC;
	wire [15:0] net_PipelinetoID_instr;
	wire [3:0] net_WBtoID_writeAddr;
	wire [15:0] net_WBtoID_writeData;
	wire net_WBtoID_RegWrite;
	
	wire net_IDtoPipeline_doJmp;
	wire net_IDtoPipeline_RegWrite;
	wire net_IDtoPipeline_MemtoReg;
	wire net_IDtoPipeline_branch;
	wire net_IDtoPipeline_MemRead;
	wire net_IDtoPipeline_MemWrite;
	wire net_IDtoPipeline_ALUSrc1;
	wire net_IDtoPipeline_ALUSrc2;
	wire [3:0] net_IDtoPipeline_ALUOp;
	wire [15:0] net_IDtoPipeline_readData1;
	wire [15:0] net_IDtoPipeline_readData2;
	wire [15:0] net_IDtoPipeline_signExt;
	wire [15:0] net_IDtoPipeline_mt;
	wire [3:0] net_IDtoPipeline_rs;
	wire [3:0] net_IDtoPipeline_rt;
	wire [3:0] net_IDtoPipeline_writeDst;
	wire net_IDtoPipeline_RorNot;
	wire [15:0] net_IDtoPipeline_PC;

	wire net_PipelinetoEX_RegWrite;
	wire net_PipelinetoEX_MemtoReg;
	wire net_PipelinetoEX_branch;
	wire net_PipelinetoEX_MemRead;
	wire net_PipelinetoEX_MemWrite;
	wire net_PipelinetoEX_ALUSrc1;
	wire net_PipelinetoEX_ALUSrc2;
	wire [3:0] net_PipelinetoEX_ALUOp;
	wire [15:0] net_PipelinetoEX_readData1;
	wire [15:0] net_PipelinetoEX_readData2;
	wire [15:0] net_PipelinetoEX_signExt;
	wire [15:0] net_PipelinetoEX_mt;
	wire [3:0] net_PipelinetoEX_rs;
	wire [3:0] net_PipelinetoEX_rt;
	wire [3:0] net_PipelinetoEX_writeDst;
	wire net_PipelinetoEX_RorNot;
	wire [15:0] net_PipelinetoEX_PC;

	wire [1:0] net_ForwardtoEX_FA;
	wire [1:0] net_ForwardtoEX_FB;
	
	wire [15:0] net_EXtoPipeline_ALUresult;
	wire net_EXtoPipeline_zero;
	wire net_EXtoPipeline_sign;
	wire [15:0] net_EXtoPipeline_branchAddr;
	wire [15:0] net_EXtoPipeline_mt;
	wire [3:0] net_EXtoPipeline_writeDst;
	wire net_EXtoPipeline_RegWrite;
	wire net_EXtoPipeline_MemtoReg;
	wire net_EXtoPipeline_Branch;
	wire net_EXtoPipeline_MemRead;
	wire net_EXtoPipeline_MemWrite;
	
	wire [15:0] net_PipelinetoMEM_ALUresult;
	wire net_PipelinetoMEM_zero;
	wire net_PipelinetoMEM_sign;
	wire [15:0] net_PipelinetoMEM_branchAddr;
	wire [15:0] net_PipelinetoMEM_mt;
	wire [3:0] net_PipelinetoMEM_writeDst;
	wire net_PipelinetoMEM_RegWrite;
	wire net_PipelinetoMEM_MemtoReg;
	wire net_PipelinetoMEM_Branch;
	wire net_PipelinetoMEM_MemRead;
	wire net_PipelinetoMEM_MemWrite;
	
	wire [15:0] net_MEMtoPipeline_readData;
	wire net_MEMtoPipeline_doBra;
	wire net_MEMtoPipeline_RegWrite;
	wire net_MEMtoPipeline_MemtoReg;
	wire [15:0] net_MEMtoPipeline_ALUresult;
	wire [3:0] net_MEMtoPipeline_writeDst;
	wire [15:0] net_MEMtoID_branchAddr;
	
	wire net_PipelinetoWB_RegWrite;
	wire net_PipelinetoWB_MemtoReg;
	wire [15:0] net_PipelinetoWB_readData;
	wire [15:0] net_PipelinetoWB_ALUresult;
	wire [3:0] net_PipelinetoWB_writeDst;
	

//General layout
//Fetch -> IF/ID -> Decode -> ID/EX -> Execute -> EX/MEM -> Memory -> MEM/WB -> Write Back
	
	InstructionFetch i_fetch(
		.clk(clk),
		.branchAddr(net_MEMtoIF_branchAddr),
		.jumpPC(net_IDtoIF_JumpPC), 
		.jumpInstr(net_IDtoIF_JumpInstr), 
		.doJmp(net_IDtoIF_doJump), 
		.doBra(net_MEMtoIF_doBra), 
		.PC(net_IFtoPipeline_PC), 
		.instr(net_IFtoPipeline_instr),
		.reset(reset));
		
	IFtoID_Buffer i_IFID(
		.clk(clk), 
		.pcIn(net_IFtoPipeline_PC), 
		.instrIn(net_IFtoPipeline_instr), 
		.pcOut(net_PipelinetoID_PC), 
		.instrOut(net_PipelinetoID_instr));


	InstructionDecode i_decode(
		.clk(clk), 
		.pcIn(net_PipelinetoID_PC), 
		.instrIn(net_PipelinetoID_instr), 
		.writeAddr(net_WBtoID_writeDst), 
		.writeData(net_WBtoID_writeData), //you have it MEMtoID on board
		.RegWrite_from_WB(net_WBtoID_RegWrite),
		.doJmp(net_IDtoPipeline_doJmp),  
		.jumpPC(net_IDtoIF_JumpPC), 
		.jumpInstr(net_IDtoIF_JumpInstr), 
		.RegWrite(net_IDtoPipeline_RegWrite), 
		.MemtoReg(net_IDtoPipeline_MemtoReg), 
		.branch(net_IDtoPipeline_branch), 
		.MemRead(net_IDtoPipeline_MemRead), 
		.MemWrite(net_IDtoPipeline_MemWrite),  
		.ALUSrc1(net_IDtoPipeline_ALUSrc1), 
		.ALUSrc2(net_IDtoPipeline_ALUSrc2), 
		.ALUOp(net_IDtoPipeline_ALUOp), 
		.readData1(net_IDtoPipeline_readData1), 
		.readData2(net_IDtoPipeline_readData2), 
		.signExt(net_IDtoPipeline_signExt), 
		.rs(net_IDtoPipeline_rs),
		.rt(net_IDtoPipeline_rt),
		.writeDst(net_IDtoPipeline_writeDst), 
		.RorNot(net_IDtoPipeline_RorNot), 
		.mt(net_IDtoPipeline_mt), 
		.pcOut(net_IDtoPipeline_PC),
		.reset(reset));

	IDtoEX_Buffer i_IDEX(
		.clk(clk), 
		.pcIn(net_IDtoPipeline_PC), 
		.RegWriteIn(net_IDtoPipeline_RegWrite), 
		.MemtoRegIn(net_IDtoPipeline_MemtoReg), 
		.BranchIn(net_IDtoPipeline_branch), 
		.MemReadIn(net_IDtoPipeline_MemRead), 
		.MemWriteIn(net_IDtoPipeline_MemWrite), 
		.ALUSrc1In(net_IDtoPipeline_ALUSrc1), 
		.ALUSrc2In(net_IDtoPipeline_ALUSrc2), 
		.ALUOpIn(net_IDtoPipeline_ALUOp), 
		.readData1In(net_IDtoPipeline_readData1), 
		.readData2In(net_IDtoPipeline_readData2), 
		.signExtendIn(net_IDtoPipeline_signExt), 
		.RsIn(net_IDtoPipeline_rs),
		.RtIn(net_IDtoPipeline_rt),
		.writeDstIn(net_IDtoPipeline_writeDst), 
		.mtIn(net_IDtoPipeline_mt),
		.pcOut(net_PipelinetoEX_PC), 
		.RegWriteOut(net_PipelinetoEX_RegWrite), 
		.MemtoRegOut(net_PipelinetoEX_MemtoReg), 
		.BranchOut(net_PipelinetoEX_branch), 
		.MemReadOut(net_PipelinetoEX_MemRead), 
		.MemWriteOut(net_PipelinetoEX_MemWrite), 
		.ALUSrc1Out(net_PipelinetoEX_ALUSrc1), 
		.ALUSrc2Out(net_PipelinetoEX_ALUSrc2), 
		.ALUOpOut(net_PipelinetoEX_ALUOp), 
		.readData1Out(net_PipelinetoEX_readData1), 
		.readData2Out(net_PipelinetoEX_readData2), 
		.signExtendOut(net_PipelinetoEX_signExt), 
		.RsOut(net_PipelinetoEX_rs),
		.RtOut(net_PipelinetoEX_rt),
		.writeDstOut(net_PipelinetoEX_writeDst), 
		.mtOut(net_PipelinetoEX_mt));
		
		Execution i_exec(
			.PCin(net_PipelinetoEX_PC), 
			.ALUSrc1(net_PipelinetoEX_ALUSrc1), 
			.ALUSrc2(net_PipelinetoEX_ALUSrc2), 
			.RS(net_PipelinetoEX_readData1), 
			.RT(net_PipelinetoEX_readData2), 
			.signExt(net_PipelinetoEX_signExt), 
			.ALUOp(net_PipelinetoEX_ALUOp), 
			.ALUresult(net_EXtoPipeline_ALUresult), 
			.zero(net_EXtoPipeline_zero), 
			.sign(net_EXtoPipeline_sign), 
			.branchAddr(net_EXtoPipeline_branchAddr),
			.mtIn(net_PipelinetoEX_mt), 
			.ForA(net_ForwardtoEX_FA),
			.ForB(net_ForwardtoEX_FB),
			.MEMALUresult(net_MEMtoPipeline_ALUresult),
			.WBwriteData(net_WBtoID_writeData),
			.writeDstIn(net_PipelinetoEX_writeDst), 
			.RegWriteIn(net_PipelinetoEX_RegWrite), 
			.MemtoRegIn(net_PipelinetoEX_MemtoReg), 
			.BranchIn(net_PipelinetoEX_branch), 
			.MemReadIn(net_PipelinetoEX_MemRead), 
			.MemWriteIn(net_PipelinetoEX_MemWrite),
			.mtOut(net_EXtoPipeline_mt), 
			.writeDstOut(net_EXtoPipeline_writeDst), 
			.RegWriteOut(net_EXtoPipeline_RegWrite), 
			.MemtoRegOut(net_EXtoPipeline_MemtoReg), 
			.BranchOut(net_EXtoPipeline_Branch), 
			.MemReadOut(net_EXtoPipeline_MemRead), 
			.MemWriteOut(net_EXtoPipeline_MemWrite));
			
	ForwardingUnit i_forward(
			.IDEX_Rs(net_PipelinetoEX_rs), 
			.IDEX_Rt(net_PipelinetoEX_rt), 
			.EXMEM_Rd(net_PipelinetoMEM_writeDst), 
			.EXMEM_RegWrite(net_PipelinetoMEM_RegWrite), 
			.MEMWB_Rd(net_PipelinetoWB_writeDst), 
			.MEMWB_RegWrite(net_WBtoID_RegWrite), 
			.ForwardA(net_ForwardtoEX_FA), 
			.ForwardB(net_ForwardtoEX_FB));
			
	EXtoMEM_Buffer i_EXMEM(
		.clk(clk), 
		.mtIn(net_EXtoPipeline_mt), 
		.writeDstIn(net_EXtoPipeline_writeDst), 
		.RegWriteIn(net_EXtoPipeline_RegWrite), 
		.MemtoRegIn(net_EXtoPipeline_MemtoReg), 
		.BranchIn(net_EXtoPipeline_Branch), 
		.MemReadIn(net_EXtoPipeline_MemRead), 
		.MemWriteIn(net_EXtoPipeline_MemWrite),
		.ALUresultIn(net_EXtoPipeline_ALUresult),
		.zeroIn(net_EXtoPipeline_zero),
		.signIn(net_EXtoPipeline_sign),
		.branchAddrIn(net_EXtoPipeline_branchAddr),
		.ALUresultOut(net_PipelinetoMEM_ALUresult),
		.zeroOut(net_PipelinetoMEM_zero),
		.signOut(net_PipelinetoMEM_sign),
		.branchAddrOut(net_PipelinetoMEM_branchAddr),
		.mtOut(net_PipelinetoMEM_mt), 
		.writeDstOut(net_PipelinetoMEM_writeDst), 
		.RegWriteOut(net_PipelinetoMEM_RegWrite), 
		.MemtoRegOut(net_PipelinetoMEM_MemtoReg), 
		.BranchOut(net_PipelinetoMEM_Branch), 
		.MemReadOut(net_PipelinetoMEM_MemRead), 
		.MemWriteOut(net_PipelinetoMEM_MemWrite));
		
	Memory i_Mem(
		.clk(clk),
		.Branch(net_PipelinetoMEM_Branch),
		.MemRead(net_PipelinetoMEM_MemRead),
		.MemWrite(net_PipelinetoMEM_MemWrite),
		.zero(net_PipelinetoMEM_zero),
		.ALUresultIn(net_PipelinetoMEM_ALUresult),
		.readData(net_MEMtoPipeline_readData),
		.doBra(net_MEMtoPipeline_doBra),
		.mt(net_PipelinetoMEM_mt),
		.RegWriteIn(net_PipelinetoMEM_RegWrite),
		.MemtoRegIn(net_PipelinetoMEM_MemtoReg),
		.writeDstIn(net_PipelinetoMEM_writeDst),
		.branchAddrIn(net_PipelinetoMEM_branchAddr),
		.RegWriteOut(net_MEMtoPipeline_RegWrite),
		.MemtoRegOut(net_MEMtoPipeline_MemtoReg),
		.ALUresultOut(net_MEMtoPipeline_ALUresult),
		.writeDstOut(net_MEMtoPipeline_writeDst),
		.branchAddrOut(net_MEMtoPipeline_branchAddr),
		.reset(reset));
		
	MEMtoWB_Buffer i_MEMWB(
		.clk(clk),
		.RegWriteIn(net_MEMtoPipeline_RegWrite),
		.MemtoRegIn(net_MEMtoPipeline_MemtoReg),
		.readDataIn(net_MEMtoPipeline_readData),
		.ALUresultIn(net_MEMtoPipeline_ALUresult),
		.writeDstIn(net_MEMtoPipeline_writeDst),
		.RegWriteOut(net_PipelinetoWB_RegWrite),
		.MemtoRegOut(net_PipelinetoWB_MemtoReg),
		.readDataOut(net_PipelinetoWB_readData),
		.ALUresultOut(net_PipelinetoWB_ALUresult),
		.writeDstOut(net_PipelinetoWB_writeDst));
		
	WriteBack i_writeback(
		.MemtoReg(net_PipelinetoWB_MemtoReg),
		.memData(net_PipelinetoWB_readData),
		.ALUresult(net_PipelinetoWB_ALUresult),
		.writeDstIn(net_PipelinetoWB_writeDst),
		.RegWriteIn(net_PipelinetoWB_RegWrite),
		.writeDstOut(net_WBtoID_writeDst),
		.RegWriteOut(net_WBtoID_RegWrite),
		.writeData(net_WBtoID_writeData));
		
/*Things needed in Fetch:
- Program Counter
- Instruction Memory
- Adder to increment PC
*/

/*Things needed in IF/ID
- Incremented PC
- Instruction
*/

/*Things needed in decode
- Register file
- Sign extend
- Control Unit
NOTE: Our implementation can get tricky here due to us having to access registers ($mt, $mr, $b) that may not be in the instruction.
*/

/*Things needed in ID/EX
- Control for WB, MEM, EX stages
- Incremented PC
- Contents of Rs, Rt
- Rs, Rt, Rd
--> Rs and Rd will be fighting over the writeback destination slot
- Sign extended immediate
*/

/*Things needed in execute
- ALU
- Adder for branch address calculation
*/

/*Things needed in EX/MEM
- Control for WB, MEM stages
- Branch address
- ALUresult and zero bit
- Contents of Rs
- Write back destination
*/

/*Things needed in memory
- Memory (duh)
- Branch stuff
*/

/*Things needed in MEM/WB
- Control for WB
- Write back destination
- Memory contents
- 
*/
endmodule
